/*
* $Id: InspectManager.java 278 2011-03-04 22:31:44Z volok-aleksej@yandex.ru $
*
* Copyright 2008-2011 by Volokitin Alexey
* All rights reserved
*
*/
package apiary.db.managers;

import java.util.*;
import java.io.*;

import apiary.Apiary;
import apiary.db.InspectStore;
import apiary.db.JournalStore;
import apiary.db.InspectStore.InspectRecord;
import apiary.db.JournalStore.JournalRecord;
import apiary.ui.journal.InspectValue;
import apiary.ui.journal.UserFieldForm.UserField;
import apiary.ui.journal.JournalForm.JournalValue;

/**
 * Inspect database manager
 * @author lexus
 */
public class InspectManager
{
    public class InspectManagerRecord
    {
        public JournalRecord journal;
        public Vector inspects;

        public InspectManagerRecord(JournalRecord record) {
            journal = record;
            inspects = new Vector();
        }
    }

    /** instance class */
    private static InspectManager instance = null;
    /** common inspect database */
    private JournalStore journalStore;
    /** hive's inspect database */
    private InspectStore inspectStore;
    /** maximal inspect identificator */
    private int maxIdInspect;
    /** list of inspects */
    private Vector dbInspect;
    
    /**
     * Gets instance class
     * @return instance class
     */
    protected static InspectManager getInstance() {
        return instance;
    }

    /** list of queen bee's states */
    private Hashtable qbStates;
    /** list of diseases */
    private Hashtable diseases;

    /**
     * Constructor
     */
    public InspectManager() {
        instance = this;
        qbStates = new Hashtable();
        diseases = new Hashtable();
        journalStore = new JournalStore();
        inspectStore = new InspectStore();
        dbInspect = new Vector();
        readInspects();
        FillQBStates();
        FillDiseases();
    }

    /**
     * Adds inspect at list.
     * Converts inspect to database format and adds at list.
     * @param idFamily identificator of family
     * @param journal common inspect
     * @param inspectH list of hive's inspects
     * @return binary data that describe inspect
     */
    protected byte[] addInspect(int idFamily, JournalValue journal, Vector inspectH) {
        maxIdInspect = nextIdInpect();
        int idRecord = 0;
        if(journal.userFields.size() > 0)
            idRecord = FieldsValueManager.getInstance().nextIdRecord();
        JournalRecord journalRecord = (JournalRecord) journalStore.getRecord();
        journalRecord.idJournal = maxIdInspect;
        journalRecord.idRecord = idRecord;
        journalRecord.idFamily = idFamily;
        ConvertData.JournalValueToRecord(journal, journalRecord);
        InspectManagerRecord iMRecord = new InspectManagerRecord(journalRecord);
        dbInspect.addElement(iMRecord);
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            DataOutputStream dis = new DataOutputStream(outputStream);
            outputStream.write(journalRecord.getData());
            dis.writeInt(inspectH.size());
            for(int i = 0; i < inspectH.size(); i++) {
                InspectValue inspectValue = (InspectValue) inspectH.elementAt(i);
                InspectRecord inspect = (InspectRecord) inspectStore.getRecord();
                inspect.idJournal = maxIdInspect;
                ConvertData.InspectValueToRecord(inspectValue, inspect);
                outputStream.write(inspect.getData());
                iMRecord.inspects.addElement(inspect);
            }
            for(int i = 0; i < journal.userFields.size(); i++) {
                UserField field = (UserField) journal.userFields.elementAt(i);
                byte[] fieldValue = FieldsValueManager.getInstance().addFieldValue(field, idRecord);
                if(fieldValue == null)
                    continue;
                outputStream.write(fieldValue);
            }
            return outputStream.toByteArray();
        } catch (IOException ex) {}
        return null;
    }

    /**
     * Adds inspect at list.
     * Data will be parsed and created new inspect object.
     * @param data binary data that describe inspect
     */
    protected void addInspect(byte[] data) {
        JournalRecord journalRecord = (JournalRecord) journalStore.getRecord();
        int offset = journalRecord.setData(data);
        InspectManagerRecord inspectRecord = new InspectManagerRecord(journalRecord);
        dbInspect.addElement(inspectRecord);
        if(maxIdInspect < journalRecord.idJournal)
            maxIdInspect = journalRecord.idJournal;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos.write(data, offset, data.length - offset);
        int sizeInspect = 0;
        try {
            byte[] newData = baos.toByteArray();
            ByteArrayInputStream bais = new ByteArrayInputStream(newData);
            DataInputStream dis = new DataInputStream(bais);
            sizeInspect = dis.readInt();
            offset += newData.length - dis.available();
        }catch(IOException ex){}
        for(int i = sizeInspect; i > 0; i--){
            baos.reset();
            baos.write(data, offset, data.length - offset);
            InspectRecord inspect = (InspectRecord) inspectStore.getRecord();
            offset += inspect.setData(baos.toByteArray());
            inspectRecord.inspects.addElement(inspect);
        }
        FieldsValueManager.getInstance().addFieldValues(data, offset);
    }

    /**
     * Changes inspect at list.
     * Converts inspect to database format and change in list.
     * @param idJournal identificator of inspect
     * @param value common inspect
     * @param inspects list of hive's inspects
     * @return binary data that describe inspect
     */
    protected byte[] changeInspect(int idJournal, JournalValue value, Vector inspects) {
        int idRecord = 0;
        InspectManagerRecord inspectRecord = getInspect(idJournal);
        if(inspectRecord == null)
            return null;
        ConvertData.JournalValueToRecord(value, inspectRecord.journal);
        if(value.userFields.size() > 0 && inspectRecord.journal.idRecord == 0)
            idRecord = FieldsValueManager.getInstance().nextIdRecord();
        else if(value.userFields.size() > 0 && inspectRecord.journal.idRecord != 0)
            idRecord = inspectRecord.journal.idRecord;
        inspectRecord.journal.idRecord = idRecord;
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            DataOutputStream dos = new DataOutputStream(outputStream);
            outputStream.write(inspectRecord.journal.getData());
            dos.writeInt(inspects.size());
            inspectRecord.inspects.removeAllElements();
            for(int i = 0; i < inspects.size(); i++) {
                InspectValue inspect = (InspectValue) inspects.elementAt(i);
                InspectRecord record = (InspectRecord) inspectStore.getRecord();
                record.idJournal = idJournal;
                ConvertData.InspectValueToRecord(inspect, record);
                inspectRecord.inspects.addElement(record);
                outputStream.write(record.getData());
            }
            for(int i = 0; i < value.userFields.size(); i++) {
                UserField field = (UserField) value.userFields.elementAt(i);
                byte[] fieldValue = FieldsValueManager.getInstance().changeFieldValue(field, idRecord);
                if(fieldValue == null)
                    continue;
                outputStream.write(fieldValue);
            }
            return outputStream.toByteArray();
        }catch(IOException ioe){}
        return null;
    }
    
    /**
     * Changes inspect at list.
     * Data will be parsed and change inspect object.
     * @param data binary data that describe inspect
     */
    protected void changeInspect(byte[] data) {
        JournalRecord journalRecord = (JournalRecord) journalStore.getRecord();
        int offset = journalRecord.setData(data);
        InspectManagerRecord inspectRecord = getInspect(journalRecord.idJournal);
        if(inspectRecord == null)
            return;
        inspectRecord.journal = journalRecord;
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        baos.write(data, offset, data.length - offset);
        int sizeInspect = 0;
        try {
            byte[] newData = baos.toByteArray();
            ByteArrayInputStream bais = new ByteArrayInputStream(newData);
            DataInputStream dis = new DataInputStream(bais);
            sizeInspect = dis.readInt();
            offset += newData.length - dis.available();
        }catch(IOException ex){}
        inspectRecord.inspects.removeAllElements();
        for(int i = sizeInspect; i > 0; i--){
            baos.reset();
            baos.write(data, offset, data.length - offset);
            InspectRecord inspect = (InspectRecord) inspectStore.getRecord();
            offset += inspect.setData(baos.toByteArray());
            inspectRecord.inspects.addElement(inspect);
        }
        FieldsValueManager.getInstance().changeFieldValues(data, offset);
    }

    /**
     * Delete inspect from list.
     * @param value binary data that describe inspect
     */
    protected void deleteInspect(byte[] value) {
        try {
            ByteArrayInputStream bais = new ByteArrayInputStream(value);
            DataInputStream dis = new DataInputStream(bais);
            deleteInspectFromList(dis.readInt());
        } catch (IOException ex) {}
    }
    /**
     * Delete inspect from list.
     * @param id identificator of inspect
     */
    protected byte[] deleteInspect(int id) {
        try {
            deleteInspectFromList(id);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            DataOutputStream dos = new DataOutputStream(baos);
            dos.writeInt(id);
            return baos.toByteArray();
        } catch (IOException ex) {}
        return null;
    }

    /**
     * Delete inspects from list.
     * @param idFamily identificator of family
     */
    protected void deleteInspects(int idFamily) {
        for(int i = 0; i < dbInspect.size(); i++) {
            InspectManagerRecord inspect = (InspectManagerRecord) dbInspect.elementAt(i);
            if(inspect.journal.idFamily == idFamily) {
                FieldsValueManager flmManager = FieldsValueManager.getInstance();
                flmManager.deleteValues(inspect.journal.idRecord);
                dbInspect.removeElementAt(i);
                i--;
            }
        }
    }

    /**
     * Gets common inspect of family
     * @param id identificator of inspect
     * @return common inspect
     */
    protected InspectManagerRecord getInspect(int id) {
        for(int i = 0; i < dbInspect.size(); i++) {
            InspectManagerRecord record = (InspectManagerRecord) dbInspect.elementAt(i);
            if(record.journal.idJournal == id)
                return record;
        }
        return null;
    }

    /**
     * Gets inspects of family
     * @param idFamily identificator of family
     * @return list of inspects
     */
    protected Vector getInspects(int idFamily) {
        Vector inspects = new Vector();
        for(int i = 0; i < dbInspect.size(); i++) {
            InspectManagerRecord inspect = (InspectManagerRecord) dbInspect.elementAt(i);
            if(inspect.journal.idFamily == idFamily)
                inspects.addElement(inspect);
        }
        return inspects;
    }

    /**
     * Gets queen bee's states
     * @return list of states
     */
    protected Hashtable getQBStates() {
        return qbStates;
    }

    /**
     * Gets diseases bee
     * @return list of diseases
     */
    protected Hashtable getDiseases() {
        return diseases;
    }

    /**
     * Resets all data in manager
     */
    protected void resetManager() {
        dbInspect.removeAllElements();
        maxIdInspect = 0;
        readInspects();
    }

    /**
     * Delete inspect from list.
     * @param id identificator of inspect
     */
    private void deleteInspectFromList(int id) {
        for(int i = 0; i < dbInspect.size(); i++) {
            InspectManagerRecord inspect = (InspectManagerRecord) dbInspect.elementAt(i);
            if(inspect.journal.idJournal == id) {
                FieldsValueManager flmManager = FieldsValueManager.getInstance();
                flmManager.deleteValues(inspect.journal.idRecord);
                dbInspect.removeElementAt(i);
                break;
            }
        }
    }

    /**
     * Calculates next inspect identificator
     * @return identificator
     */
    private int nextIdInpect() {
        return maxIdInspect + 1;
    }

    /**
     * Fills states of queen bee
     */
    private void FillQBStates() {
        Apiary apiary = Apiary.getInstance();
        qbStates.put(new Integer(JournalRecord.IS_DEFAULT),
                     apiary.getLocaleString("QBNoLook"));
        qbStates.put(new Integer(JournalRecord.IS_LOOK),
                     apiary.getLocaleString("QBLook"));
        qbStates.put(new Integer(JournalRecord.IS_ABSENCE),
                     apiary.getLocaleString("QBAbsence"));
        qbStates.put(new Integer(JournalRecord.IS_FETAL),
                     apiary.getLocaleString("QBFetal"));
    }
    /**
     * Fills diseases bee
     */
    private void FillDiseases() {
        Apiary apiary = Apiary.getInstance();
        diseases.put(new Integer(JournalRecord.DISEASE_HEALTHY),
                    apiary.getLocaleString("DiseaseHealty"));
        diseases.put(new Integer(JournalRecord.DISEASE_AFB),
                    apiary.getLocaleString("DiseaseAFB"));
        diseases.put(new Integer(JournalRecord.DISEASE_EFB),
                    apiary.getLocaleString("DiseaseEFB"));
        diseases.put(new Integer(JournalRecord.DISEASE_PFB),
                    apiary.getLocaleString("DiseasePFB"));
        diseases.put(new Integer(JournalRecord.DISEASE_VARROA),
                    apiary.getLocaleString("DiseaseVarroa"));
        diseases.put(new Integer(JournalRecord.DISEASE_ACARINE),
                    apiary.getLocaleString("DiseaseAcarine"));
        diseases.put(new Integer(JournalRecord.DISEASE_NOSEMA),
                    apiary.getLocaleString("DiseaseNosema"));
        diseases.put(new Integer(JournalRecord.DISEASE_CHALKBROOD),
                    apiary.getLocaleString("DiseaseChalkbrood"));
        diseases.put(new Integer(JournalRecord.DISEASE_STONEBROOD),
                    apiary.getLocaleString("DiseaseStonebrood"));
        diseases.put(new Integer(JournalRecord.DISEASE_ABPV),
                    apiary.getLocaleString("DiseaseABPV"));
        diseases.put(new Integer(JournalRecord.DISEASE_MILK),
                    apiary.getLocaleString("DiseaseMILK"));
        diseases.put(new Integer(JournalRecord.DISEASE_PBV),
                    apiary.getLocaleString("DiseasePBV"));
        diseases.put(new Integer(JournalRecord.DISEASE_BQCV),
                    apiary.getLocaleString("DiseaseBQCV"));
        diseases.put(new Integer(JournalRecord.DISEASE_CPV),
                    apiary.getLocaleString("DiseaseCPV"));
        diseases.put(new Integer(JournalRecord.DISEASE_CWV),
                    apiary.getLocaleString("DiseaseCWV"));
        diseases.put(new Integer(JournalRecord.DISEASE_DWV),
                    apiary.getLocaleString("DiseaseDWV"));
        diseases.put(new Integer(JournalRecord.DISEASE_SBV),
                    apiary.getLocaleString("DiseaseSBV"));
        diseases.put(new Integer(JournalRecord.DISEASE_CCD),
                    apiary.getLocaleString("DiseaseCCD"));
        diseases.put(new Integer(JournalRecord.DISEASE_GAFN),
                    apiary.getLocaleString("DiseaseGafn"));
        diseases.put(new Integer(JournalRecord.DISEASE_SALMON),
                    apiary.getLocaleString("DiseaseSalmon"));
        diseases.put(new Integer(JournalRecord.DISEASE_SEPT),
                    apiary.getLocaleString("DiseaseSept"));
        diseases.put(new Integer(JournalRecord.DISEASE_COLI),
                    apiary.getLocaleString("DiseaseColi"));
        diseases.put(new Integer(JournalRecord.DISEASE_CITRO),
                    apiary.getLocaleString("DiseaseCitro"));
        diseases.put(new Integer(JournalRecord.DISEASE_SPIRO),
                    apiary.getLocaleString("DiseaseSpiro"));
        diseases.put(new Integer(JournalRecord.DISEASE_FILO),
                    apiary.getLocaleString("DiseaseFilo"));
        diseases.put(new Integer(JournalRecord.DISEASE_MELONOZ),
                    apiary.getLocaleString("DiseaseMelanoz"));
        diseases.put(new Integer(JournalRecord.DISEASE_AMEBA),
                    apiary.getLocaleString("DiseaseAmeba"));
        diseases.put(new Integer(JournalRecord.DISEASE_CRITI),
                    apiary.getLocaleString("DiseaseCriti"));
        diseases.put(new Integer(JournalRecord.DISEASE_MERM),
                    apiary.getLocaleString("DiseaseMerm"));
        diseases.put(new Integer(JournalRecord.DISEASE_PIE),
                    apiary.getLocaleString("DiseasePie"));
        diseases.put(new Integer(JournalRecord.DISEASE_EAP),
                    apiary.getLocaleString("DiseaseEAP"));
        diseases.put(new Integer(JournalRecord.DISEASE_GREG),
                    apiary.getLocaleString("DiseaseGreg"));
        diseases.put(new Integer(JournalRecord.DISEASE_SEN),
                    apiary.getLocaleString("DiseaseSen"));
    }
    
    /**
     * Reads inspect database
     */
    private void readInspects() {
        Enumeration journalEnum = journalStore.getRecordsEnumeration();
        do {
            if(!journalEnum.hasMoreElements())
                break;
            JournalRecord record = (JournalRecord) journalEnum.nextElement();
            dbInspect.addElement(new InspectManagerRecord(record));
            if(maxIdInspect < record.idJournal)
                maxIdInspect = record.idJournal;
        } while(true);
        Enumeration inspectEnum = inspectStore.getRecordsEnumeration();
        do {
            if(!inspectEnum.hasMoreElements())
                break;
            InspectRecord record = (InspectRecord) inspectEnum.nextElement();
            for(int i = 0; i < dbInspect.size(); i++) {
                InspectManagerRecord inspect = (InspectManagerRecord) dbInspect.elementAt(i);
                if(inspect.journal.idJournal == record.idJournal) {
                    inspect.inspects.addElement(record);
                    break;
                }
            }
        } while(true);
    }
}
